package cn.elegent.lock.redis;

import cn.elegent.lock.ElegentLock;
import cn.elegent.lock.config.LockConfig;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁实现类
 */
@ConditionalOnProperty(prefix = "elegent.lock",name = "type",havingValue = "redis")
@Slf4j
public class RedisLock implements ElegentLock {

    private RedissonClient [] redissonClients;

    @Autowired
    private LockConfig lockConfig;


    @PostConstruct
    public void init(){
        if(lockConfig.getHost()==null){
            lockConfig.setHost(new String[]{"127.0.0.1:6379"});
        }
        //初始化
        redissonClients=new RedissonClient[ lockConfig.getHost().length  ];

        for(int i=0;i<lockConfig.getHost().length;i++){
            Config config = new Config();
            config.useSingleServer().setAddress( "redis://"+lockConfig.getHost()[i] );
            redissonClients[i] = Redisson.create(config);
        }
    }



    /**
     * 加锁
     *
     * @param lockName
     */
    public boolean lock(String lockName,int ttl,boolean isSpin) {
        //红锁
        boolean isLock=true;
        RLock lock = getRLock(lockName);
        if(isSpin){  //自旋
        	if(ttl == -1) {
        		lock.lock();
        	}else {
        		lock.lock(ttl,TimeUnit.SECONDS);
        	}
        }else{
            try {
            	if(ttl == -1) {
            		 isLock= lock.tryLock(lockConfig.getWait(),TimeUnit.SECONDS);
            	}else {
            		isLock= lock.tryLock(lockConfig.getWait(),ttl,TimeUnit.SECONDS);
            	}
            } catch (InterruptedException e) {
                //throw new RuntimeException(e);
                isLock = false;
            }
        }
        if(isLock){
            System.out.println(Thread.currentThread().getName()+"===redis加锁成功，锁名称：{}"+lockName);
        }
        return isLock;
    }


    /**
     * 释放锁
     *
     * @param lockName
     */
    public boolean unLock(String lockName) {
        try {
            RLock lock = getRLock(lockName);
            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"===redis释放锁成功，锁名称：{}"+lockName);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            System.out.println(Thread.currentThread().getName()+"===redis释放锁出错，锁名称：{}"+lockName);
            return false;
        }
    }

    /**
     * 是否存在锁
     *
     * @param lockName
     * @return
     */
    public boolean isLocked(String lockName) {
        RLock lock = getRLock(lockName);
        return lock.isLocked();
    }

    private RLock getRLock(String lockName){
        RLock [] rLocks=new RLock[redissonClients.length];
        for(int i=0;i<redissonClients.length;i++ ){
            rLocks[i] =  redissonClients[i].getLock(lockName);
        }
        if(rLocks.length>2){
            return new RedissonRedLock( rLocks );
        }else{
            if(redissonClients.length==0) return null;
            return redissonClients[0].getLock(lockName);
        }
    }

}
